package cn.tedu.charging.order.service.impl;

import cn.tedu.charging.common.pojo.JsonResult;
import cn.tedu.charging.common.pojo.param.GunStatusUpdateParam;
import cn.tedu.charging.common.pojo.vo.StationInfoVO;
import cn.tedu.charging.common.pojo.vo.UserInfoVO;
import cn.tedu.charging.common.utils.JsonUtils;
import cn.tedu.charging.order.constant.Constants;
import cn.tedu.charging.order.constant.MqttConstant;
import cn.tedu.charging.order.feign.DeviceClient;
import cn.tedu.charging.order.feign.UserClient;
import cn.tedu.charging.order.mqtt.MqttProducer;
import cn.tedu.charging.order.pojo.dto.ChargingDto;
import cn.tedu.charging.order.pojo.dto.StationInfoDto;
import cn.tedu.charging.order.pojo.dto.UserInfoDto;
import cn.tedu.charging.order.pojo.param.OrderAddParam;
import cn.tedu.charging.order.pojo.po.OrderMQPO;
import cn.tedu.charging.order.quartz.DeviceCheckJob;
import cn.tedu.charging.order.rabbit.RabbitMQOrderProducer;
import cn.tedu.charging.order.service.OrderService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.SchedulerException;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Slf4j
@Service
public class OrderServiceImpl implements OrderService {

    /**
     * 创建订单
     * 1. 生成订单号
     * 2. 获取场站信息和设备信息
     * 3. 获取用户车辆信息
     * 4. 给设备发送开始充电指令
     * 5. 修改充电桩的状态 为 使用中
     * @param orderAddParam
     * @return
     */
    @Override
    public String createOrder(OrderAddParam orderAddParam) {
        //创建订单的流程  自顶向下编程
       //1. 生成订单号
       String orderNo  = getOrderNo();
       //2. 获取场站信息和设备信息
       StationInfoDto stationInfoDto = getStationInfoByGunId(orderAddParam.getGunId());
       //3. 获取用户车辆信息
       UserInfoDto userInfoDto =  getUserInfoByUserId(orderAddParam.getUserId());
       //4. 修改充电桩的状态 为 使用中
       Boolean success = updateGunStatusBusy(orderAddParam.getGunId());

        //创建自检定时任务 16:45 + 1 = 16:46
        //要保证在正常情况下，设备能收到指令，并且能返回响应
        //放到最后相对比较靠谱

        //5. 创建自检定时任务
        log.debug("创建设备自检任务，入参:订单号:{},枪id:{}",orderNo,orderAddParam.getGunId());
        try {
            DeviceCheckJob deviceCheckJob = new DeviceCheckJob(orderNo,orderAddParam.getGunId());
        } catch (SchedulerException e) {
            //可以抛一个业务异常，通过全局异常处理器处理
            //告诉用户 给用户提示信息 订单创建失败，不要提示具体代码异常信息
            log.error("设备自检任务创建失败");
        }

        //6. 给设备发送开始充电指令
        startCharging(orderNo,orderAddParam.getPileId(),orderAddParam.getGunId());
       //7. 给RabbitMQ发送延迟消息,用来处理设备故障导致的超时订单
       sendOrderMessage(orderNo);
       return orderNo;
    }

    @Autowired
    private RabbitMQOrderProducer rabbitMQOrderProducer;

    /**
     * 给RabbitMQ发送延迟消息,用来处理设备故障导致的超时订单
     */
    private void sendOrderMessage(String orderNo){
        OrderMQPO orderMQPO = new OrderMQPO();
        orderMQPO.setOrderNo(orderNo);
        rabbitMQOrderProducer.sendOrder(orderMQPO);
    }

    @Autowired
    private MqttProducer mqttProducer;

    /**
     * 给设备发送开始充电指令
     * @param orderNo
     * @param pileId
     * @param gunId
     */
    private void startCharging(String orderNo, Integer pileId, Integer gunId) {
        //topic 前缀 + 桩id  不加枪的id,设备去订阅这个topic,接收所有发到这个桩上的消息
        String topic = MqttConstant.TOPIC_START_CHARGING_PREFIX + "/" + pileId;
        ChargingDto chargingDto = new ChargingDto();
        chargingDto.setOrderNo(orderNo);
        chargingDto.setPileId(pileId);
        chargingDto.setGunId(gunId);
        chargingDto.setMsg(Constants.START_CHARGING);
        String json = JsonUtils.toJson(chargingDto);
        log.debug("订单服务发送开始充电指令到设备topic:{},消息:{}",topic,json);
        Boolean send = mqttProducer.send(topic, json);
        log.debug("订单服务发送开始充电指令到设备topic:{},消息:{},结果:{}",topic,json,send);
        //如果发送失败,需要重试,需要告警
    }

    @Autowired
    private DeviceClient deviceClient;

    /**
     * 修改充电桩的状态 为 使用中
     * @param gunId
     * @return
     */
    private Boolean updateGunStatusBusy(Integer gunId) {
        GunStatusUpdateParam param = new GunStatusUpdateParam();
        param.setGunId(gunId);
        param.setStatus(Constants.GUN_STATS_BUSY);//魔数 代码里不要有魔数,应该用常量或者枚举
        JsonResult<Boolean> jsonResult = deviceClient.updateGunStatus(param);
        if (jsonResult != null) {
            return jsonResult.getData();
        }
        return false;
    }

    /**
     * private 最小
     * 默认
     * 保护
     * public
     */
    @Autowired
    private UserClient userClient;

    /**
     * 获取用户车辆信息
     * 订单服务调用用户服务的什么?获取信息
     * @param userId
     * @return
     */
    private UserInfoDto getUserInfoByUserId(Integer userId) {
        JsonResult<UserInfoVO> userCarInfo = userClient.getUserCarInfo(userId);
        if (userCarInfo != null) {
            UserInfoVO data = userCarInfo.getData();
            if (data != null) {
                UserInfoDto userInfoDto = new UserInfoDto();
                userInfoDto.setCarId(data.getCarId());
                return userInfoDto;
            }
        }
        return null;
    }





    /**
     * 通过枪id 获取场站信息
     * @param gunId
     * @return
     */
    private StationInfoDto getStationInfoByGunId(Integer gunId) {
        JsonResult<StationInfoVO> stationInfo = deviceClient.getStationInfo(gunId);
        if (stationInfo != null) {
            StationInfoVO data = stationInfo.getData();
            if (data != null) {
                StationInfoDto stationInfoDto = new StationInfoDto();
                //stationInfoDto.setStationId(data.getStationId());
                //todo copyProperties 底层实现
                BeanUtils.copyProperties(data,stationInfoDto);
                return stationInfoDto;
            }
        }
        return null;
    }

    /**
     * 生成订单号
     * @return
     */
    private String getOrderNo() {
        return "666";
    }
}
